﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Registration;

using CodeStash.Common.DataAccess.Repository;
using CodeStash.Common.DataAccess.EntityFramework;
using CodeStash.Common.DataAccess.UnitOfWork;
using CodeStash.Mef;
using CodeStash.Services;
using System.ComponentModel.Composition;
using CodeStash.Common.DataAccess.AspMembership;
using CodeStash.Services.Implementation;
using CodeStash.Services.Contracts;
using CodeStash.ExtesionMethods;
using log4net;
using System.Diagnostics;
using System.Reflection;
using CodeStash.Utils;
using CodeStash.Filters;


namespace CodeStash
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        private static CompositionContainer container;
        private ContentWatcher contentWatcher = new ContentWatcher();
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);
        

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            //http://community.codesmithtools.com/CodeSmith_Community/b/tdupont/archive/2011/03/01/error-handling-and-customerrors-and-mvc3-oh-my.aspx
            HandleErrorAttribute handleError = container.GetExport<HandleErrorExFilter>().Value;
            handleError.View = "_Error";
            filters.Add(handleError);
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("favicon.ico"); //Causes MefControllerFactory to die unless this is here
 
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
                new { controller = @"[^\.]*" }
            );

        }

        private static void SetupControllerFactory()
        {
            RegistrationBuilder context = new RegistrationBuilder();

            context.OfType(typeof(HandleErrorExFilter)).
                            Export(builder => builder.AsContractType(typeof(HandleErrorExFilter)))
                            .SetCreationPolicy(CreationPolicy.NonShared);

            context.OfType(typeof(Repository<>)).
                Export(builder => builder.AsContractType(typeof(IRepository<>)))
                .SetCreationPolicy(CreationPolicy.NonShared);

            context.OfType(typeof(GetUserForRestService)).
                Export(builder => builder.AsContractType(typeof(IGetUserForRestService)))
                .SetCreationPolicy(CreationPolicy.NonShared);

            context.OfType(typeof(CodeStashEntities)).
                Export(builder => builder.AsContractType(typeof(IUnitOfWork)))
                .SetCreationPolicy(CreationPolicy.NonShared);

            context.OfType(typeof(Log4NetLoggerService)).
                Export(builder => builder.AsContractType(typeof(ILoggerService)))
                .SetCreationPolicy(CreationPolicy.Shared);

            context.OfType(typeof(AccountMembershipService)).
                Export(builder => builder.AsContractType(typeof(IMembershipService)))
                .SetCreationPolicy(CreationPolicy.NonShared);


            context.OfType(typeof(MembershipDataProvider)).
                Export(builder => builder.AsContractType(typeof(IMembershipDataProvider)))
                .SetCreationPolicy(CreationPolicy.NonShared);

            context.OfType(typeof(FormsAuthenticationService)).
                Export(builder => builder.AsContractType(typeof(IFormsAuthenticationService)))
                .SetCreationPolicy(CreationPolicy.NonShared);

            context.OfType(typeof(TagCloudService)).
                Export(builder => builder.AsContractType(typeof(ITagCloudService)))
                .SetCreationPolicy(CreationPolicy.NonShared);

            context.Where(type => typeof(IController).IsAssignableFrom(type) && !type.IsAbstract).
                Export(builder => builder.AsContractType<IController>().
                        AddMetadata("ControllerName", type => type.GetControllerName()))
                .SetCreationPolicy(CreationPolicy.NonShared);

            AggregateCatalog catalog = new AggregateCatalog(
                new AssemblyCatalog(typeof(Repository<>).Assembly, context),
                new AssemblyCatalog(typeof(MefControllerFactory).Assembly, context));

            container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);
            IControllerFactory factory = container.GetExportedValue<IControllerFactory>();

            ControllerBuilder.Current.SetControllerFactory(factory);
        }



        protected void Application_Start()
        {
            SetupControllerFactory();

            AreaRegistration.RegisterAllAreas();
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            StoreContentHashCodes();

        }

   



        private void StoreContentHashCodes()
        {
            
            Log.Info("Beginning to compute hashes of content files...");

            Stopwatch timer = Stopwatch.StartNew();
            int count = contentWatcher.WatchPath(HttpRuntime.AppDomainAppPath + "Scripts");
            count += contentWatcher.WatchPath(HttpRuntime.AppDomainAppPath + "Content");
            timer.Stop();

            Log.Info(string.Format("Content hashes calculated: {0}, time-elapsed: {1}.", count, timer.Elapsed));
        }

    }
}